package com.hzw.saas.service.storage.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrSplitter;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.storage.IResourceFileService;
import com.hzw.saas.api.storage.IResourceFolderService;
import com.hzw.saas.api.storage.bo.ResourceFolderConflictBO;
import com.hzw.saas.api.storage.bo.ResourceFolderStructBO;
import com.hzw.saas.api.storage.constants.StorageConsts;
import com.hzw.saas.api.storage.enums.ResourceStatusEnum;
import com.hzw.saas.api.storage.exception.FolderConflictException;
import com.hzw.saas.common.config.query.LogicQuery;
import com.hzw.saas.common.config.util.MybatisPlusUtil;
import com.hzw.saas.common.util.Json;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.PathUtils;
import com.hzw.saas.common.util.SnowFlakeUtil;
import com.hzw.saas.common.util.constants.PathConsts;
import com.hzw.saas.common.util.enums.AssertEnum;
import com.hzw.saas.common.util.enums.ConflictModeEnum;
import com.hzw.saas.common.util.exception.ForbiddenException;
import com.hzw.saas.service.storage.mapper.ResourceFolderMapper;
import com.hzw.saas.service.storage.model.ResourceFolder;
import com.hzw.saas.service.storage.util.StorageUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 文件目录默认实现
 * <p>
 * 目录存储约束规则:
 * 1. 同一父目录下不可存在多个同名子目录（正常状态）
 * 2. 同一父目录下可能存在多个同名子目录（正常一个，回收或删除状态多个）
 * 3. 恢复被回收目录时，若上级目录被删除，则提示恢复目录至指定父目录
 * 4. 恢复被回收目录时，若恢复至父目录有同名目录时，则需要更改目录名
 * 5. 被删除资源无法更新状态至正常或回收
 *
 * @author zzl
 * @since 02/25/2021
 */
@Service(ResourceFolderServiceImpl.BEAN_NAME)
@RequiredArgsConstructor
@Slf4j
public class ResourceFolderServiceImpl extends ServiceImpl<ResourceFolderMapper, ResourceFolder> implements IResourceFolderService, IService<ResourceFolder> {

    public static final String BEAN_NAME = "resourceFolderServiceImpl";

    @Resource
    private IResourceFileService fileService;

    @PostConstruct
    public void init() {

    }

    @Override
    public String getPathByPid(String pid) {
        if (StrUtil.isBlank(pid)) {
            return null;
        }
        if (StorageUtil.isRootId(pid)) {
            return PathConsts.SLASH;
        }
        ResourceFolder folder = this.getFolderDO(
            select(ResourceFolder::getSupId, ResourceFolder::getName),
            pid, LogicQuery.ne(ResourceStatusEnum.DELETED.groupCodes()),
            AssertEnum.FOUND
        );
        if (Objects.isNull(folder)) return "";
        String currentPath = folder.getName().concat(PathConsts.SLASH);
        return this.getPathByPid(folder.getSupId()).concat(currentPath);
    }

    @Override
    public boolean isValidPidPath(String pidPath) {
        List<String> ids = StrSplitter.splitByRegex(pidPath, PathConsts.ALL_SLASH_PATTERN,
            -1, true, true);
        return isValidPidPath(ids);
    }

    @Override
    public boolean isValidPidPath(List<String> pidPath) {
        if (CollUtil.isEmpty(pidPath)) {
            return false;
        }
        List<ResourceFolder> folders = this.listFolderDOs(this.select(ResourceFolder::getPid, ResourceFolder::getSupId),
            pidPath, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));

        Map<String, ResourceFolder> folderMap = folders.stream()
            .collect(Collectors.toMap(ResourceFolder::getPid, v -> v, (k1, k2) -> k1));

        for (int i = 0; i < pidPath.size(); i++) {
            String pid = pidPath.get(i);
            if (i == 0 && StorageUtil.isRootId(pid)) {
                continue;
            }
            ResourceFolder folder = folderMap.get(pid);
            if (folder == null) {
                return false;
            }
            if (i > 0 && !Objects.equals(folder.getSupId(), pidPath.get(i - 1))) {
                return false;
            }
        }
        return true;
    }

    @Override
    public String getPathByPidPath(String pidPath) {
        List<String> ids = StrSplitter.splitByRegex(pidPath, PathConsts.ALL_SLASH_PATTERN, -1, true, true);
        return this.getPathByPidPath(ids);
    }

    @Override
    public String getPathByPidPath(List<String> pidPath) {
        if (CollUtil.isEmpty(pidPath)) {
            return "";
        }

        List<ResourceFolder> folders = this.listFolderDOs(this.select(ResourceFolder::getPid, ResourceFolder::getName),
            pidPath, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode())
        );
        Map<String, ResourceFolder> folderMap = folders.stream()
            .collect(Collectors.toMap(ResourceFolder::getPid, v -> v, (k1, k2) -> k1));

        StringBuilder result = new StringBuilder("");
        for (int i = 0; i < pidPath.size(); i++) {
            String pid = pidPath.get(i);
            if (StorageUtil.isRootId(pid)) {
                result.append(PathConsts.SLASH);
                continue;
            }
            ResourceFolder folderDO = folderMap.get(pid);
            if (Objects.isNull(folderDO)) {
                return null;
            }
            if ((i > 0) && !Objects.equals(folderDO.getSupId(), pidPath.get(i - 1))) {
                return null;
            }
            result.append(PathConsts.SLASH).append(folderDO.getName());
        }
        return result.toString();
    }

    @Override
    public ResourceFolderStructBO getFolder(String pid, AssertEnum assertEnum) {
        return this.getFolder(pid, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()), assertEnum);
    }

    @Override
    public ResourceFolderStructBO getFolder(String pid, LogicQuery<Integer> status, AssertEnum assertEnum) {
        ResourceFolder folderDO = this.getFolderDO(this.select(), pid, status, assertEnum);
        return MapperUtil.nf().map(folderDO, ResourceFolderStructBO.class);
    }

    @Override
    public List<ResourceFolderStructBO> listFolders(List<String> pidList) {
        return this.listFolders(pidList, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));
    }

    @Override
    public List<ResourceFolderStructBO> listFolders(List<String> pidList, LogicQuery<Integer> status) {
        List<ResourceFolder> folderDOs = this.listFolderDOs(this.select(), pidList, status);
        return MapperUtil.nf().mapAsList(folderDOs, ResourceFolderStructBO.class);
    }

    @Override
    public List<ResourceFolderStructBO> listSubFolders(String supId) {
        return this.listSubFolders(supId, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));
    }

    @Override
    public List<ResourceFolderStructBO> listSubFolders(String supId, LogicQuery<Integer> status) {
        List<ResourceFolder> folderDOList = this.listSubFolderDOs(this.select(), supId, status);
        return MapperUtil.nf().mapAsList(folderDOList, ResourceFolderStructBO.class);
    }

    @Override
    public List<ResourceFolderStructBO> listSubFolders(List<String> supIdList) {
        return listSubFolders(supIdList, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));
    }

    @Override
    public List<ResourceFolderStructBO> listSubFolders(List<String> supIdList, LogicQuery<Integer> status) {
        List<ResourceFolder> result = this.listSubFolderDOs(this.select(), supIdList, status);
        return MapperUtil.nf().mapAsList(result, ResourceFolderStructBO.class);
    }

    @Override
    public List<ResourceFolderStructBO> listUserFolders(String userId, String spaceId, LogicQuery<Integer> status) {
        List<ResourceFolder> folderDOList = this.listUserFolderDOs(this.select(), userId, spaceId, status);
        return MapperUtil.nf().mapAsList(folderDOList, ResourceFolderStructBO.class);
    }

    @Override
    public List<String> listSubFolderPids(String supId, LogicQuery<Integer> status) {
        List<ResourceFolder> folders = this.listSubFolderDOs(this.select(ResourceFolder::getPid), supId, status);
        return folders.stream().map(ResourceFolder::getPid).collect(Collectors.toList());
    }

    @Override
    public List<String> listSubFolderPids(List<String> supIds, LogicQuery<Integer> status) {
        List<ResourceFolder> folders = this.listSubFolderDOs(this.select(ResourceFolder::getPid), supIds, status);
        return folders.stream().map(ResourceFolder::getPid).collect(Collectors.toList());
    }

    @Override
    public boolean isNameExist(String supId, String folderName, LogicQuery<Integer> status) {
        if (StrUtil.isBlank(supId)) {
            return false;
        }
        LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryBySupId(this.select(), supId, folderName, status);
        Integer count = query.count();
        return !Objects.equals(count, 0);
    }

    @Override
    public long countSize(String pid, LogicQuery<Integer> status, LogicQuery<Integer> integrity) {
        return this.countSize(ListUtil.toList(pid), status, integrity);
    }

    @Override
    public long countSize(List<String> pidList, LogicQuery<Integer> status, LogicQuery<Integer> integrity) {
        if (CollUtil.isEmpty(pidList)) {
            return 0L;
        }
        long totalSize = 0L;
        // 统计文件大小
        totalSize += fileService.countSizeBySupId(pidList, status, integrity);
        // 统计子目录
        List<String> subPids = this.listSubFolderPids(pidList, status);
        totalSize += this.countSize(subPids, status, integrity);
        return totalSize;
    }

    @Override
    public boolean checkAuthOwn(String userId, String folderId) {
        Integer count = super.lambdaQuery()
            .select(ResourceFolder::getPid)
            .eq(ResourceFolder::getPid, folderId)
            .eq(ResourceFolder::getCreatorId, userId)
            .count();
        return !Objects.equals(count, 0);
    }

    @Override
    public boolean checkAuthOwn(String userId, List<String> folderIdList) {
        if (CollUtil.isEmpty(folderIdList)) {
            return true;
        }
        List<ResourceFolder> list = super.lambdaQuery()
            .select(ResourceFolder::getPid, ResourceFolder::getCreatorId)
            .in(ResourceFolder::getPid, folderIdList)
            .list();
        long count = list.stream().filter(folder -> !Objects.equals(folder.getCreatorId(), userId)).count();
        return count == 0;
    }

    @Override
    public void assertAuthOwn(String userId, List<String> folderIdList) {
        boolean auth = this.checkAuthOwn(userId, folderIdList);
        Assert.isTrue(auth, () -> new ForbiddenException("存在无权限目录"));
    }

    /**
     * 目录创建校验：
     * 1. 必要参数：父目录，目录名
     * 2. 父目录存在且状态正常
     * 3. 父目录下无正常状态的同名文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResourceFolderStructBO createFolder(ResourceFolderStructBO folderBO, ConflictModeEnum conflictHandle) {
        ResourceFolder folderDO = MapperUtil.nf().map(folderBO, ResourceFolder.class);
        folderDO = this.saveFolderDO(folderDO, conflictHandle);
        return MapperUtil.nf().map(folderDO, ResourceFolderStructBO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<ResourceFolderStructBO> createFoldersByPath(String supId, String path) {
        List<String> folderNameList = PathUtils.listNames(path);
        List<ResourceFolder> folderDOList = new ArrayList<>();
        String originSupId = supId;
        for (String folderName : folderNameList) {
            ResourceFolder folderBO = new ResourceFolder();
            folderBO.setSupId(supId);
            folderBO.setName(folderName);
            folderBO = this.saveFolderDO(folderBO, ConflictModeEnum.DELETE_SRC);
            folderDOList.add(folderBO);
            supId = Objects.requireNonNull(folderBO).getPid();
        }
        log.debug("路径创建完成(supId: {}, path: {})", originSupId, path);
        return MapperUtil.nf().mapAsList(folderDOList, ResourceFolderStructBO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copyFolder(String srcPid, String tarSupId, String newName, ConflictModeEnum conflictHandle) {
        // 待处理目录
        ResourceFolder srcFolder = this.getFolderDO(this.select(), srcPid, AssertEnum.FOUND);
        ResourceFolder tarSupFolder = this.getFolderDO(this.select(), tarSupId, AssertEnum.FOUND);
        // 当目标父目录为自身，或为自身的子目录时，停止操作
        if (this.isRelationShip(srcPid, tarSupFolder)) return;
        this.copyFolderDO(srcFolder, tarSupFolder, newName, conflictHandle);
        log.debug("复制目录({srcPid: {}, tarSupId: {}, newName: {}})完成.", srcPid, tarSupId, newName);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copyFolders(List<String> srcPidList, String tarSupId, ConflictModeEnum conflictHandle) {
        if (CollUtil.isEmpty(srcPidList)) return;
        List<ResourceFolder> srcFolders = this.listFolderDOs(this.select(), srcPidList,
            LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));
        ResourceFolder tarSupFolder = this.getFolderDO(this.select(), tarSupId, AssertEnum.FOUND);
        List<String> supIds = this.listSupPids(tarSupId);
        supIds.add(tarSupId);
        for (ResourceFolder srcFolder : srcFolders) {
            // 当目标父目录为自身，或为自身的子目录时，停止操作
            if (supIds.contains(srcFolder.getPid())) continue;
            this.copyFolderDO(srcFolder, tarSupFolder, null, conflictHandle);
        }
        log.debug("批量复制目录({tarSupId: {}})完成.", tarSupId);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void moveFolder(String pid, String tarSupId, String newName, ConflictModeEnum conflictHandle) {
        // 待处理目录
        ResourceFolder srcFolder = this.getFolderDO(this.select(), pid, AssertEnum.FOUND);
        ResourceFolder tarSupFolder = this.getFolderDO(this.select(), tarSupId, AssertEnum.IGNORE);
        // 当目标父目录为自身，或为自身的子目录时，停止操作
        if (this.isRelationShip(pid, tarSupFolder)) return;
        this.moveFolderDO(srcFolder, tarSupFolder, newName, conflictHandle);
        log.debug("移动目录({srcPid: {}, tarSupId: {}, newName: {}})完成.", pid, tarSupId, newName);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void moveFolders(List<String> pidList, String tarSupId, ConflictModeEnum conflictHandle) {
        if (CollUtil.isEmpty(pidList)) return;
        List<ResourceFolder> srcFolders = this.listFolderDOs(this.select(), pidList, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));
        ResourceFolder tarSupFolder = this.getFolderDO(this.select(), tarSupId, AssertEnum.FOUND);
        List<String> supIds = this.listSupPids(tarSupId);
        supIds.add(tarSupId);
        for (ResourceFolder srcFolder : srcFolders) {
            // 当目标父目录为自身，或为自身的子目录时，停止操作
            if (supIds.contains(srcFolder.getPid())) continue;
            this.moveFolderDO(srcFolder, tarSupFolder, null, conflictHandle);
        }
        log.debug("批量移动目录({tarSupId: {}})完成.", tarSupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void renameFolder(String pid, String newName, ConflictModeEnum conflictHandle) {
        Assert.isTrue(StrUtil.isNotBlank(newName), "目录名不可为空");
        this.moveFolder(pid, null, newName, conflictHandle);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recycleFolder(String pid) {
        if (StrUtil.isBlank(pid))
            return;
        // 回收文件即变更文件状态为300
        // 只回收200状态
        log.debug("recycle folder({})...", pid);
        this.lambdaUpdate().eq(ResourceFolder::getPid, pid)
            .eq(ResourceFolder::getStatus, ResourceStatusEnum.NORMAL.getCode())
            .set(ResourceFolder::getStatus, ResourceStatusEnum.RECYCLED.getCode())
            .set(ResourceFolder::getUpdateTime, new Date())
            .update();
        // 回收子文件
        fileService.recycleSubFiles(pid);
        // 回收子目录
        this.recycleSubFolders(pid);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recycleFolders(List<String> pidList) {
        if (CollectionUtil.isEmpty(pidList)) return;
        // 批量回收目录
        log.debug("recycle folders({})...", JSONUtil.toJsonStr(pidList));
        this.lambdaUpdate().in(ResourceFolder::getPid, pidList)
            .eq(ResourceFolder::getStatus, ResourceStatusEnum.NORMAL.getCode())
            .set(ResourceFolder::getStatus, ResourceStatusEnum.RECYCLED.getCode())
            .update();
        for (String pid : pidList) {
            fileService.recycleSubFiles(pid);
            this.recycleSubFolders(pid);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recycleSubFolders(String supId) {
        log.debug("recycle sub files({supId: {}})...", supId);
        List<String> subPidList = this.listSubFolderPids(supId, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));
        if (CollectionUtil.isEmpty(subPidList)) return;
        // 批量回收当前目录
        this.lambdaUpdate().eq(ResourceFolder::getSupId, supId)
            .eq(ResourceFolder::getStatus, ResourceStatusEnum.NORMAL.getCode())
            .set(ResourceFolder::getStatus, ResourceStatusEnum.RECYCLED_LINKED.getCode())
            .set(ResourceFolder::getUpdateTime, new Date())
            .update();
        for (String subPid : subPidList) {
            // 回收子文件
            fileService.recycleSubFiles(subPid);
            // 回收子目录
            this.recycleSubFolders(subPid);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restoreFolder(String pid, String tarSupId, String newName, ConflictModeEnum conflictHandle) {
        ResourceFolder folder = this.getFolderDO(this.select(), pid, LogicQuery.eq(ResourceStatusEnum.RECYCLED.groupCodes()), AssertEnum.FOUND);
        ResourceFolder tarSupFolder = this.getFolderDO(this.select(), tarSupId, AssertEnum.IGNORE);
        this.restoreFolderDO(folder, tarSupFolder, newName, conflictHandle);
        log.debug("恢复目录({srcPid: {}, tarSupId: {}, newName: {}})完成.", pid, tarSupId, newName);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restoreFolders(List<String> pidList, String tarSupId, ConflictModeEnum conflictHandle) {
        if (CollUtil.isEmpty(pidList)) return;
        List<ResourceFolder> folders = this.listFolderDOs(this.select(), pidList, LogicQuery.eq(ResourceStatusEnum.RECYCLED.groupCodes()));
        ResourceFolder tarSupFolder = this.getFolderDO(this.select(), tarSupId, AssertEnum.IGNORE);
        // 循环恢复
        for (ResourceFolder folder : folders) {
            this.restoreFolderDO(folder, tarSupFolder, null, conflictHandle);
        }
        log.debug("批量恢复目录({tarSupId: {}})完成.", tarSupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void restoreSubFolders(String supId, String tarSupId, ConflictModeEnum conflictHandle) {
        List<ResourceFolder> subFolders = this.listSubFolderDOs(this.select(), supId,
            LogicQuery.eq(ResourceStatusEnum.RECYCLED_LINKED.getCode()));
        if (CollUtil.isEmpty(subFolders)) return;
        ResourceFolder tarSupFolder = this.getFolderDO(this.select(), tarSupId, AssertEnum.FOUND);
        for (ResourceFolder subFolder : subFolders) {
            this.restoreFolderDO(subFolder, tarSupFolder, null, conflictHandle);
        }
        log.debug("批量恢复子目录({tarSupId: {}})完成.", tarSupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFolder(String pid) {
        if (StrUtil.isBlank(pid))
            return;
        // 删除文件即变更文件状态为400
        // 排除400状态
        log.debug("delete folder({})...", pid);
        List<Integer> deletedStatus = ResourceStatusEnum.DELETED.groupCodes();
        this.lambdaUpdate().eq(ResourceFolder::getPid, pid)
            .notIn(ResourceFolder::getStatus, deletedStatus)
            .set(ResourceFolder::getStatus, ResourceStatusEnum.DELETED.getCode())
            .update();
        // 回收子文件
        fileService.deleteSubFiles(pid);
        // 回收子目录
        this.deleteSubFolder(pid);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFolders(List<String> pidList) {
        if (CollectionUtil.isEmpty(pidList))
            return;
        // 批量回收当前目录
        // 排除400状态
        log.debug("delete folders({})...", JSONUtil.toJsonStr(pidList));
        List<Integer> deletedStatus = ResourceStatusEnum.DELETED.groupCodes();
        this.lambdaUpdate().in(ResourceFolder::getPid, pidList)
            .notIn(ResourceFolder::getStatus, deletedStatus)
            .set(ResourceFolder::getStatus, ResourceStatusEnum.DELETED.getCode())
            .update();
        for (String pid : pidList) {
            // 删除子文件
            fileService.deleteSubFiles(pid);
            // 删除子目录
            this.deleteSubFolder(pid);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSubFolder(String supId) {
        List<Integer> deletedStatus = ResourceStatusEnum.DELETED.groupCodes();
        List<String> subPidList = this.listSubFolderPids(supId, LogicQuery.ne(deletedStatus));
        if (CollectionUtil.isEmpty(subPidList)) return;
        // 批量回收当前目录
        // 排除400状态
        log.debug("delete sub folders({supId: {}})...", supId);
        this.lambdaUpdate().eq(ResourceFolder::getSupId, supId)
            .notIn(ResourceFolder::getStatus, deletedStatus)
            // TODO: ZZL@09/24/2021 状态401
            .set(ResourceFolder::getStatus, ResourceStatusEnum.DELETED.getCode())
            .update();
        for (String subPid : subPidList) {
            // 删除子文件
            fileService.deleteSubFiles(subPid);
            // 删除子目录
            this.deleteSubFolder(subPid);
        }
    }

    @Override
    public void resurrectFolder(String pid, String tarSupId, String newName, ConflictModeEnum conflictHandle) {
        // TODO: ZZL@07/01/2021
    }

    @Override
    public void resurrectFolders(List<String> pidList, String tarSupId, ConflictModeEnum conflictHandle) {
        // TODO: ZZL@07/01/2021
    }

    // =============================================== private do method =============================================== //

    /**
     * 调用此方法前请先判断pid是否为root id
     *
     * @param pid root ID
     * @return root
     */
    private ResourceFolderStructBO getRootFolder(String pid) {
        ResourceFolder rootFolderDO = this.getRootFolderDO(pid);
        return MapperUtil.nf().map(rootFolderDO, ResourceFolderStructBO.class);
    }

    /**
     * 调用此方法前请先判断pid是否为root id
     *
     * @param pid root ID
     * @return root
     */
    private ResourceFolder getRootFolderDO(String pid) {
        String[] params = StorageUtil.parseRootId(pid);
        ResourceFolder root = new ResourceFolder();
        root.setPid(pid);
        root.setCreatorId(params[1]);
        root.setEditorId(params[1]);
        root.setSpaceId(params[0]);
        root.setSupId(pid);
        root.setName(StorageConsts.ROOT_NAME);
        root.setStatus(ResourceStatusEnum.NORMAL.getCode());
        return root;
    }

    /**
     * 根据目录ID获取目录信息
     *
     * @param pid        目录ID
     * @param cols       指定查找的属性列，null-查找所有
     * @param assertEnum 结果检查, null或IGNORE-跳过结果检查
     * @return 目录信息
     */
    private ResourceFolder getFolderDO(SFunction<ResourceFolder, ?>[] cols, String pid, AssertEnum assertEnum) {
        return this.getFolderDO(cols, pid, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()), assertEnum);
    }

    /**
     * 根据目录ID获取目录信息
     *
     * @param pid        目录ID
     * @param cols       指定查找的属性列，null-查找所有
     * @param status     资源状态, null-过滤400状态
     * @param assertEnum 结果检查, null或IGNORE-跳过结果检查
     * @return 目录信息
     */
    private ResourceFolder getFolderDO(SFunction<ResourceFolder, ?>[] cols, String pid, LogicQuery<Integer> status, AssertEnum assertEnum) {
        ResourceFolder folderInfo;
        if (StrUtil.isBlank(pid)) {
            folderInfo = null;
        } else if (StorageUtil.isRootId(pid)) {
            folderInfo = getRootFolderDO(pid);
        } else {
            LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryByPid(cols, pid, status);
            folderInfo = query.one();
        }
        AssertEnum.assertResult(assertEnum, folderInfo, String.format("目录(%s)", pid));
        return folderInfo;
    }

    /**
     * @param pidList 必要
     * @param status  可选
     */
    private List<ResourceFolder> listFolderDOs(SFunction<ResourceFolder, ?>[] cols, List<String> pidList, LogicQuery<Integer> status) {
        if (CollUtil.isEmpty(pidList)) {
            return new ArrayList<>();
        }
        if (pidList.size() <= MybatisPlusUtil.MAX_IN_PARAMS) {
            LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryByPids(cols, pidList, status);
            return query.list();
        }
        List<ResourceFolder> result = new ArrayList<>();
        List<List<String>> pidListGroup = ListUtil.partition(pidList, MybatisPlusUtil.MAX_IN_PARAMS);
        for (List<String> list : pidListGroup) {
            LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryByPids(cols, list, status);
            result.addAll(query.list());
        }
        return result;
    }

    /**
     * @param cols   可选
     * @param supId  必要
     * @param status 可选
     * @return
     */
    private List<ResourceFolder> listSubFolderDOs(SFunction<ResourceFolder, ?>[] cols, String supId, LogicQuery<Integer> status) {
        if (StrUtil.isBlank(supId)) {
            return new ArrayList<>();
        }
        LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryBySupId(cols, supId, null, status);
        return query.list();
    }

    /**
     * @param cols   可选
     * @param supIds 必要
     * @param status 可选
     * @return
     */
    private List<ResourceFolder> listSubFolderDOs(SFunction<ResourceFolder, ?>[] cols, List<String> supIds, LogicQuery<Integer> status) {
        if (CollUtil.isEmpty(supIds)) {
            return new ArrayList<>();
        }
        if (supIds.size() <= MybatisPlusUtil.MAX_IN_PARAMS) {
            LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryBySupIds(cols, supIds, status);
            return query.list();
        }
        List<ResourceFolder> result = new ArrayList<>();
        List<List<String>> supIdListGroup = ListUtil.partition(supIds, MybatisPlusUtil.MAX_IN_PARAMS);
        for (List<String> list : supIdListGroup) {
            LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryBySupIds(cols, list, status);
            result.addAll(query.list());
        }
        return result;
    }

    /**
     * @param userId  可选
     * @param spaceId 可选
     * @param status  可选
     */
    private List<ResourceFolder> listUserFolderDOs(SFunction<ResourceFolder, ?>[] cols, String userId, String spaceId, LogicQuery<Integer> status) {
        LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryBySpace(cols, userId, spaceId, status);
        return query.list();
    }


    private List<String> listSupPids(String pid) {
        List<String> supIds = new ArrayList<>();
        if (pid == null || StorageUtil.isRootId(pid)) {
            return supIds;
        }
        ResourceFolder folderDO = this.getFolderDO(this.select(ResourceFolder::getSupId), pid, AssertEnum.IGNORE);
        if (folderDO == null) {
            return supIds;
        }
        if (StorageUtil.isRootId(folderDO.getSupId())) {
            return supIds;
        }
        supIds.add(folderDO.getSupId());
        supIds.addAll(this.listSupPids(folderDO.getSupId()));
        return supIds;
    }

    private ResourceFolder saveFolderDO(ResourceFolder folderDO, ConflictModeEnum conflictHandle) {
        log.debug("save folder info({})...", folderDO);
        if (Objects.isNull(folderDO)) {
            return null;
        }
        this.checkSaveParams(folderDO);
        this.checkSupFolder(folderDO);
        return this.dealNameConflict(folderDO, conflictHandle, renamedFolder -> {
            super.save(renamedFolder);
            log.debug("save folder info({}) completed.", renamedFolder);
            return renamedFolder;
        });
    }

    private void saveFolderDOs(List<ResourceFolder> folderDOList, ConflictModeEnum conflictHandle) {
        log.debug("bath save folder info...");
        if (CollUtil.isEmpty(folderDOList)) {
            return;
        }
        this.checkSaveParams(folderDOList);
        this.checkSupFolder(folderDOList);
        for (ResourceFolder folderDO : folderDOList) {
            this.dealNameConflict(folderDO, conflictHandle, renamedFolder -> {
                this.save(renamedFolder);
                log.debug("save folder info({}) completed.", renamedFolder);
                return renamedFolder;
            });
        }
    }

    private void saveFolderDOs(List<ResourceFolder> folderDOList, String tarSupId, ConflictModeEnum conflictHandle) {
        log.debug("bath save folder info...");
        if (CollUtil.isEmpty(folderDOList)) {
            return;
        }
        this.checkSaveParams(folderDOList);
        this.checkSupFolder(folderDOList, tarSupId);
        for (ResourceFolder folderDO : folderDOList) {
            this.dealNameConflict(folderDO, conflictHandle, renamedFolder -> {
                super.save(renamedFolder);
                log.debug("save folder info({}) completed.", Json.toJsonString(renamedFolder));
                return renamedFolder;
            });
        }
    }

    private ResourceFolder updateFolderDoOnMoving(ResourceFolder folder2Update, ConflictModeEnum conflictHandle) {
        if (Objects.isNull(folder2Update)) {
            return null;
        }
        // 更新
        return this.dealNameConflict(folder2Update, conflictHandle, renamedFolder -> {
            this.updateFolderInfoOnMoving(folder2Update);
            return renamedFolder;
        });
    }

    private void updateFolderInfoOnMoving(ResourceFolder folder2Update) {
        ResourceFolder entity = new ResourceFolder();
        entity.setPid(folder2Update.getPid());
        entity.setSpaceId(folder2Update.getSpaceId());
        entity.setSupId(folder2Update.getSupId());
        entity.setName(folder2Update.getName());
        entity.setStatus(folder2Update.getStatus());
        entity.setCreatorId(folder2Update.getCreatorId());
        entity.setEditorId(folder2Update.getEditorId());
        super.updateById(entity);
    }

    private void copyFolderDO(ResourceFolder srcFolder, ResourceFolder tarSupFolder, String newName, ConflictModeEnum conflictHandle) {
        String srcPid = srcFolder.getPid();
        this.getCopyFolderReady(srcFolder, tarSupFolder, newName);
        if (Objects.nonNull(tarSupFolder)) {
            this.checkSupFolder(srcFolder, tarSupFolder);
        }
        // 复制保存
        ResourceFolder copyFolder = this.saveFolderDO(srcFolder, conflictHandle);
        // 如果创建的目录仍为原目录自身，则停止复制操作
        if (Objects.equals(srcPid, Objects.requireNonNull(copyFolder).getPid())) {
            return;
        }
        // 复制子文件
        this.fileService.copySubFiles(srcPid, copyFolder.getPid(), conflictHandle);
        // 复制子目录
        List<ResourceFolder> subFolders = this.listSubFolderDOs(this.select(), srcPid, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));
        for (ResourceFolder subFolder : subFolders) {
            this.copyFolderDO(subFolder, copyFolder, null, conflictHandle);
        }
    }

    private void moveFolderDO(ResourceFolder srcFolder, ResourceFolder tarSupFolder, String newName, ConflictModeEnum conflictHandle) {
        String srcPid = srcFolder.getPid();
        boolean needMove = this.getMoveFolderReady(srcFolder, tarSupFolder, newName);
        if (!needMove) return;
        if (Objects.nonNull(tarSupFolder)) {
            this.checkSupFolder(srcFolder, tarSupFolder);
        } else {
            this.checkSupFolder(srcFolder);
        }
        ResourceFolder movedFolder = this.updateFolderDoOnMoving(srcFolder, conflictHandle);
        if (Objects.equals(srcPid, Objects.requireNonNull(movedFolder).getPid())) {
            return;
        }
        // 若移动后的目录更新为目标父目录下的同名目录，则批量更新原目录中的子文件和目录
        // 更新子文件
        this.fileService.moveSubFiles(srcPid, movedFolder.getPid(), conflictHandle);
        // 更新子目录
        List<ResourceFolder> subFolders = this.listSubFolderDOs(this.select(), srcPid, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));
        // 检查参数
        for (ResourceFolder subFolder : subFolders) {
            this.moveFolderDO(subFolder, movedFolder, null, conflictHandle);
        }
    }

    private void restoreFolderDO(ResourceFolder srcFolder, ResourceFolder tarSupFolder, String newName, ConflictModeEnum conflictHandle) {
        String srcPid = srcFolder.getPid();
        this.getRestoreFolderReady(srcFolder, tarSupFolder, newName);
        if (Objects.nonNull(tarSupFolder)) {
            this.checkSupFolder(srcFolder, tarSupFolder);
        } else {
            this.checkSupFolder(srcFolder);
        }
        ResourceFolder restoredFolder = this.updateFolderDoOnMoving(srcFolder, conflictHandle);

        // 若恢复后的目录更新为目标父目录下的同名目录，则批量更新原目录中的子文件和目录
        // 更新子文件
        this.fileService.restoreSubFiles(srcPid, Objects.requireNonNull(restoredFolder).getPid(), conflictHandle);
        // 更新子目录
        List<ResourceFolder> subFolders = this.listSubFolderDOs(this.select(), srcPid, LogicQuery.eq(ResourceStatusEnum.RECYCLED_LINKED.getCode()));
        for (ResourceFolder subFolder : subFolders) {
            this.restoreFolderDO(subFolder, restoredFolder, null, conflictHandle);
        }
    }

    // ================================================ private method ================================================ //

    @SafeVarargs
    private final SFunction<ResourceFolder, ?>[] select(SFunction<ResourceFolder, ?>... cols) {
        return cols;
    }

    private LambdaQueryChainWrapper<ResourceFolder> buildQueryByPid(SFunction<ResourceFolder, ?>[] cols,
                                                                    String pid, LogicQuery<Integer> status) {
        LambdaQueryChainWrapper<ResourceFolder> query = super.lambdaQuery().eq(ResourceFolder::getPid, pid);
        if (ArrayUtil.isNotEmpty(cols)) {
            query.select(cols);
        }
        StorageUtil.addStatusCondition(query, status);
        MybatisPlusUtil.limitOne(query);
        return query;
    }

    private LambdaQueryChainWrapper<ResourceFolder> buildQueryByPids(SFunction<ResourceFolder, ?>[] cols,
                                                                     List<String> pidList,
                                                                     LogicQuery<Integer> status) {
        LambdaQueryChainWrapper<ResourceFolder> query = super.lambdaQuery()
            .in(CollUtil.isNotEmpty(pidList), ResourceFolder::getPid, pidList);
        if (ArrayUtil.isNotEmpty(cols)) {
            query.select(cols);
        }
        StorageUtil.addStatusCondition(query, status);
        return query;
    }

    private LambdaQueryChainWrapper<ResourceFolder> buildQueryBySupId(SFunction<ResourceFolder, ?>[] cols,
                                                                      String supId, String name,
                                                                      LogicQuery<Integer> status) {
        LambdaQueryChainWrapper<ResourceFolder> query = super.lambdaQuery()
            .eq(StrUtil.isNotBlank(supId), ResourceFolder::getSupId, supId)
            .eq(StrUtil.isNotBlank(name), ResourceFolder::getName, name);
        if (ArrayUtil.isNotEmpty(cols)) {
            query.select(cols);
        }
        StorageUtil.addStatusCondition(query, status);
        return query;
    }

    private LambdaQueryChainWrapper<ResourceFolder> buildQueryBySupIds(SFunction<ResourceFolder, ?>[] cols,
                                                                       List<String> supIdList,
                                                                       LogicQuery<Integer> status) {
        LambdaQueryChainWrapper<ResourceFolder> query = super.lambdaQuery()
            .in(CollUtil.isNotEmpty(supIdList), ResourceFolder::getSupId, supIdList);
        if (ArrayUtil.isNotEmpty(cols)) {
            query.select(cols);
        }
        StorageUtil.addStatusCondition(query, status);
        return query;
    }

    private LambdaQueryChainWrapper<ResourceFolder> buildQueryBySpace(SFunction<ResourceFolder, ?>[] cols,
                                                                      String userId, String spaceId,
                                                                      LogicQuery<Integer> status) {
        LambdaQueryChainWrapper<ResourceFolder> query = super.lambdaQuery()
            .eq(StrUtil.isNotBlank(userId), ResourceFolder::getCreatorId, userId)
            .eq(StrUtil.isNotBlank(spaceId), ResourceFolder::getSpaceId, spaceId);
        if (ArrayUtil.isNotEmpty(cols)) {
            query.select(cols);
        }
        StorageUtil.addStatusCondition(query, status);
        return query;
    }

    private LambdaQueryChainWrapper<ResourceFolder> buildQueryBySpaces(SFunction<ResourceFolder, ?>[] cols,
                                                                       String userId, List<String> spaceIds,
                                                                       LogicQuery<Integer> status) {
        LambdaQueryChainWrapper<ResourceFolder> query = super.lambdaQuery()
            .eq(StrUtil.isNotBlank(userId), ResourceFolder::getCreatorId, userId)
            .eq(CollUtil.isNotEmpty(spaceIds), ResourceFolder::getSpaceId, spaceIds);
        if (ArrayUtil.isNotEmpty(cols)) {
            query.select(cols);
        }
        StorageUtil.addStatusCondition(query, status);
        return query;
    }


    /**
     * 判断supPid是否为subPid的父类或为自身
     *
     * @param supPid 父目录ID
     * @param subPid 子目录ID
     * @return true or false
     */
    private boolean isRelationShip(String supPid, String subPid) {
        if (Objects.equals(supPid, subPid)) {
            return true;
        }
        ResourceFolder subFolder = super.getById(subPid);
        if (Objects.isNull(subFolder)) {
            return false;
        }
        if (Objects.equals(supPid, subFolder.getSupId())) {
            return true;
        }
        return isRelationShip(supPid, subFolder.getSupId());
    }

    /**
     * 判断supPid是否为subPid的父类或为自身
     *
     * @param supPid    父目录ID
     * @param subFolder 子目录
     * @return true or false
     */
    private boolean isRelationShip(String supPid, ResourceFolder subFolder) {
        if (Objects.isNull(subFolder)) {
            return false;
        }
        if (Objects.equals(supPid, subFolder.getPid())) {
            return true;
        }
        if (Objects.equals(supPid, subFolder.getSupId())) {
            return true;
        }
        subFolder = super.getById(subFolder.getSupId());
        return isRelationShip(supPid, subFolder);
    }


    private void checkSupFolder(ResourceFolder folderInfo) {
        this.checkSupFolder(folderInfo, folderInfo.getSupId());
    }

    private void checkSupFolder(ResourceFolder folderInfo, String supId) {
        ResourceFolder supFolder = this.getFolderDO(this.select(), supId, AssertEnum.FOUND);
        this.checkSupFolder(folderInfo, supFolder);
    }

    private void checkSupFolder(ResourceFolder folderInfo, ResourceFolder supFolder) {
        Assert.notNull(supFolder, "父目录不存在");
        folderInfo.setSupId(supFolder.getPid());
        folderInfo.setSpaceId(supFolder.getSpaceId());
        folderInfo.setCreatorId(supFolder.getCreatorId());
        folderInfo.setEditorId(supFolder.getCreatorId());
    }

    private void checkSupFolder(List<ResourceFolder> folderInfoList) {
        Map<String, List<ResourceFolder>> collect = folderInfoList.stream()
            .collect(Collectors.groupingBy(ResourceFolder::getSupId));
        collect.forEach((supId, resourceFolders) -> this.checkSupFolder(resourceFolders, supId));
    }

    private void checkSupFolder(List<ResourceFolder> folderInfoList, String supId) {
        ResourceFolder supFolder = this.getFolderDO(this.select(), supId, AssertEnum.FOUND);
        this.checkSupFolder(folderInfoList, supFolder);
    }

    private void checkSupFolder(List<ResourceFolder> folderInfoList, ResourceFolder supFolder) {
        folderInfoList.forEach(folderInfo -> this.checkSupFolder(folderInfo, supFolder));
    }

    /**
     * 校验同名约束
     *
     * @param pid
     * @param supId
     * @param name
     * @return 同名目录（非自身）, null-同名目录不存在
     */
    private ResourceFolder checkSameName(String pid, String supId, String name) {
        LambdaQueryChainWrapper<ResourceFolder> query = this.buildQueryBySupId(this.select(ResourceFolder::getPid),
            supId, name, LogicQuery.eq(ResourceStatusEnum.NORMAL.getCode()));

        List<ResourceFolder> sameNameFolders = query.list();
        return sameNameFolders.stream()
            .filter(sameNameFolder -> !Objects.equals(pid, sameNameFolder.getPid()))
            .findAny().orElse(null);
    }

    private String renameNext(String supId, String originalName) {
        int startIndex = 1;
        String namePrefixHead = originalName + PathConsts.COPY_SUFFIX_HEAD;
        List<ResourceFolder> folderList = this.lambdaQuery()
            .eq(ResourceFolder::getSupId, supId)
            .eq(ResourceFolder::getStatus, ResourceStatusEnum.NORMAL.getCode())
            .likeRight(ResourceFolder::getName, namePrefixHead)
            .orderByDesc(ResourceFolder::getName).list();
        if (folderList.isEmpty()) {
            return StrUtil.concat(true,
                namePrefixHead, String.valueOf(startIndex), PathConsts.COPY_SUFFIX_END);
        }
        String name = folderList.get(0).getName();
        String indexStr = name.substring(namePrefixHead.length(), name.lastIndexOf(PathConsts.COPY_SUFFIX_END));
        try {
            startIndex = Integer.parseInt(indexStr) + 1;
        } catch (NumberFormatException ignored) {}
        return StrUtil.concat(true,
            namePrefixHead, String.valueOf(startIndex), PathConsts.COPY_SUFFIX_END);
    }

    /**
     * 目录创建参数校验
     * 必要参数：父目录，目录名
     */
    private void checkSaveParams(ResourceFolder folder2Save) {
        // verify blank properties
        Assert.isTrue(StrUtil.isNotBlank(folder2Save.getSupId()), "父目录为空");
        Assert.isTrue(StrUtil.isNotBlank(folder2Save.getName()), "文件名为空");
        // 检查目录名是否有windows违规字符
        boolean isValidName = !FileNameUtil.containsInvalid(folder2Save.getName());
        Assert.isTrue(isValidName, "目录名含有违规字符");
        // default value
        if (StrUtil.isBlank(folder2Save.getPid())) {
            folder2Save.setPid(SnowFlakeUtil.nextIdStr());
        }
        if (Objects.isNull(folder2Save.getStatus())) {
            folder2Save.setStatus(ResourceStatusEnum.NORMAL.getCode());
        }
        folder2Save.pureTime();
    }

    private void checkSaveParams(List<ResourceFolder> folders2Save) {
        folders2Save.forEach(this::checkSaveParams);
    }

    private void getCopyFolderReady(ResourceFolder srcFolder, String tarSupId, String newName) {
        srcFolder.setPid(null);
        if (StrUtil.isNotBlank(tarSupId)) {
            srcFolder.setSupId(tarSupId);
        }
        if (StrUtil.isNotBlank(newName)) {
            // 检查文件名是否有windows违规字符
            boolean isValidName = !FileNameUtil.containsInvalid(newName);
            Assert.isTrue(isValidName, "文件名含有违规字符");
            srcFolder.setName(newName);
        }
        srcFolder.setStatus(ResourceStatusEnum.NORMAL.getCode());
    }

    private void getCopyFolderReady(ResourceFolder srcFolder, ResourceFolder tarSupFolder, String newName) {
        String tarSupId = Objects.isNull(tarSupFolder) ? null : tarSupFolder.getPid();
        this.getCopyFolderReady(srcFolder, tarSupId, newName);
    }

    private void getCopyFoldersReady(List<ResourceFolder> srcFolders, String tarSupId) {
        srcFolders.forEach(srcFolder -> this.getCopyFolderReady(srcFolder, tarSupId, null));
    }

    private boolean getMoveFolderReady(ResourceFolder srcFolder, String tarSupId, String newName) {
        if (StrUtil.isBlank(newName)) {
            newName = srcFolder.getName();
        } else {
            // 检查文件名是否有windows违规字符
            boolean isValidName = !FileNameUtil.containsInvalid(newName);
            Assert.isTrue(isValidName, "文件名含有违规字符");
        }
        if (StrUtil.isBlank(tarSupId)) {
            tarSupId = srcFolder.getSupId();
        }
        // 检查是否无需更新，父目录与名字无变动
        if (Objects.equals(srcFolder.getSupId(), tarSupId)
            && Objects.equals(srcFolder.getName(), newName)) {
            return false;
        }
        srcFolder.setSupId(tarSupId);
        srcFolder.setName(newName);
        return true;
    }

    private boolean getMoveFolderReady(ResourceFolder srcFolder, ResourceFolder tarSupFolder, String newName) {
        String tarSupId = Objects.isNull(tarSupFolder) ? null : tarSupFolder.getPid();
        return this.getMoveFolderReady(srcFolder, tarSupId, newName);
    }

    private void getMoveFoldersReady(List<ResourceFolder> srcFolders, String tarSupId) {
        srcFolders.removeIf(srcFolder -> !this.getMoveFolderReady(srcFolder, tarSupId, null));
    }

    private void getRestoreFolderReady(ResourceFolder srcFolder, String tarSupId, String newName) {
        if (StrUtil.isNotBlank(tarSupId)) {
            srcFolder.setSupId(tarSupId);
        }
        if (StrUtil.isNotBlank(newName)) {
            // 检查文件名是否有windows违规字符
            boolean isValidName = !FileNameUtil.containsInvalid(newName);
            Assert.isTrue(isValidName, "文件名含有违规字符");
            srcFolder.setName(newName);
        }
        srcFolder.setStatus(ResourceStatusEnum.NORMAL.getCode());
    }

    private void getRestoreFolderReady(ResourceFolder srcFolder, ResourceFolder tarSupFolder, String newName) {
        String tarSupId = Objects.isNull(tarSupFolder) ? null : tarSupFolder.getPid();
        this.getRestoreFolderReady(srcFolder, tarSupId, newName);
    }

    private void getRestoreFoldersReady(List<ResourceFolder> srcFolders, String tarSupId) {
        srcFolders.forEach(srcFolder -> this.getRestoreFolderReady(srcFolder, tarSupId, null));
    }


    private ResourceFolder dealNameConflict(ResourceFolder srcFolder, ConflictModeEnum conflictHandle, DealNameConflictHandler postHandle) {
        ResourceFolder sameNameFolder = this.checkSameName(srcFolder.getPid(), srcFolder.getSupId(), srcFolder.getName());
        if (Objects.nonNull(sameNameFolder)) {
            switch (conflictHandle) {
                case ALLOW:
                    log.debug("允许存在同名目录({})", sameNameFolder.getName());
                    break;
                case RENAME_SRC:
                    String rename = this.renameNext(srcFolder.getSupId(), srcFolder.getName());
                    log.debug("同名目录({})存在，重命名目录({oldName: {}, newName: {}}).", sameNameFolder.getPid(), srcFolder.getName(), rename);
                    srcFolder.setName(rename);
                    break;
                case DELETE_SRC:
                case DELETE_SRC_PURE:
                case COVER_TAR:
                case COVER_TAR_PURE:
                    log.debug("同名目录({})存在, 删除待处理目录({}).", sameNameFolder.getPid(), srcFolder.getPid());
                    ResourceFolder srcExist = super.getById(srcFolder.getPid());
                    if (Objects.nonNull(srcExist)) {
                        this.deleteFolder(srcFolder.getPid());
                    }
                    return sameNameFolder;
                case THROW_ERR:
                    ResourceFolderStructBO srcFolderBO = MapperUtil.nf().map(srcFolder, ResourceFolderStructBO.class);
                    ResourceFolderStructBO sameNameFolderBO = MapperUtil.nf().map(sameNameFolder, ResourceFolderStructBO.class);
                    throw FolderConflictException.build("存在同名目录", new ResourceFolderConflictBO(srcFolderBO, sameNameFolderBO));
            }
        }
        return postHandle.deal(srcFolder);
    }


    private interface DealNameConflictHandler {
        ResourceFolder deal(ResourceFolder renamedFolder);
    }
}
